import json
import string
import random

from django.shortcuts import redirect
from django.conf import settings
from django.http import JsonResponse
from django.utils.decorators import method_decorator

from django.contrib.auth.hashers import make_password
from django.views.decorators.csrf import csrf_exempt
from django.middleware.csrf import get_token
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
from django.contrib.auth import update_session_auth_hash
from django.core.mail import send_mail

from rest_framework import generics, permissions, status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView


import requests
from urllib.parse import urlencode, parse_qs
from .models import *
from .serializers import *
from ctbloge.apps.cms.models import Article, Collection
import random
from social_django.utils import load_strategy, load_backend





class UserProfileViewSet(viewsets.ModelViewSet):
    # serializer_class = UserProfileSerializer
    queryset = UserProfile.objects.none()  # 占位符查询集

    def get_queryset(self):
        if self.request.user.is_superuser:
            return UserProfile.objects.all()
        else:
            return UserProfile.objects.filter(id=self.request.user.id)

    def get_serializer_class(self):
        if self.action == 'blogInfo':
            return UserInfoSerializer
        else:
            return UserProfileSerializer

    def get_permissions(self):
        if self.action == 'blogInfo' or self.action == 'user_info':
            return [permissions.AllowAny()]
        else:
            return [permissions.IsAuthenticated()]

    @action(detail=False, methods=['get'])
    def blogInfo(self, request):  # 获取博主信息
        user_info = UserProfile.objects.get(is_superuser=True)
        serializer = UserInfoSerializer(user_info, context={'request': request})
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def get_nickname(self, request):
        user = request.user
        serializer = UserNicknameSerializer(user)
        return Response(serializer.data)

    # 个人中心获取用户发表的评论
    @action(detail=False, methods=['get'])
    def get_comments(self, request):
        user = request.user
        comments = Comment.objects.filter(author=user).order_by('created_date')
        serializer = CommentSerializer(comments, many=True)
        return Response(serializer.data)

    # 个人中心获取用户信息
    @action(detail=False, methods=['get'])
    def user_info(self, request):
        user = request.user
        serializer = UserProfileDetailSerializer(user)
        return Response(serializer.data)

    # 个人中心获取用户收藏文章列表
    @action(detail=False, methods=['get'])
    def get_collection(self, request):
        user = request.user
        article_ct = ContentType.objects.get_for_model(Article)
        collections = Collection.objects.filter(
            user=user,
            content_type=article_ct
        ).order_by('-created_date')
        serializer = ArticleCollectionSerializer(collections, many=True)
        return Response(serializer.data)

    # 个人中心修改用户基本信息
    @action(detail=False, methods=['get', 'put'])
    def user_basic_update(self, request):
        user = request.user
        if request.method == 'PUT':
            serializer = UserProfileUpdateSerializer(user, data=request.data, partial=True)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
        else:
            serializer = UserProfileUpdateSerializer(user)
            return Response(serializer.data)

    # 个人中心修改用户社交信息
    @action(detail=False, methods=['get', 'put'])
    def user_social_update(self, request):
        user = request.user
        if request.method == 'PUT':  # 修改
            serializer = UserSocialInfoUpdateSerializer(user, data=request.data, partial=True)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
        else:
            serializer = UserSocialInfoUpdateSerializer(user)
            return Response(serializer.data)

    # 个人中心修改用户密码
    @action(detail=False, methods=['put'])
    def user_password_update(self, request):
        user = request.user
        serializer = UserPasswordUpdateSerializer(
            data=request.data,
            context={'request': request}
        )

        serializer.is_valid(raise_exception=True)

        # 手动设置新密码
        user.set_password(serializer.validated_data['password'])
        user.save()

        # 保持会话有效性
        update_session_auth_hash(request, user)

        return Response({"tools": "密码更新成功"}, status=status.HTTP_200_OK)

    # 通过用户名获取用户信息
    # views.py 修改后的视图方法
    @action(detail=False, methods=['get'])
    def get_user_info_by_username(self, request):  # 添加request参数
        username = request.query_params.get('username')  # 正确获取查询参数

        try:
            user = UserProfile.objects.get(username=username)
            serializer = UserNicknameSerializer(user)
            return Response(serializer.data)
        except UserProfile.DoesNotExist:
            return Response(
                {"tools": "用户不存在"},
                status=status.HTTP_404_NOT_FOUND
            )


class CustomTokenObtainPairView(TokenObtainPairView):
    serializer_class = CustomTokenObtainPairSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        try:
            # 统一认证处理
            serializer.is_valid(raise_exception=True)
        except AuthenticationFailed as e:
            # 处理认证失败的具体原因
            error_detail = e.detail
            if 'tools' in error_detail:
                return Response({'error': error_detail['tools']}, status=status.HTTP_401_UNAUTHORIZED)
            return Response({'error': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        except Exception as e:
            return Response({'error': '服务器异常'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 获取用户和令牌
        user = serializer.user
        access_token = serializer.validated_data['access']
        refresh_token = serializer.validated_data['refresh']

        # 序列化用户信息
        user_serializer = UserNicknameSerializer(user)

        # 构造响应数据
        response_data = {
            'username': user.username,
            'access': access_token,
            'refresh': refresh_token,
            'message': '登录成功',
        }

        return Response(response_data, status=status.HTTP_200_OK)


class LogoutView(APIView):
    def post(self, request):
        # 可根据实际认证方式编写退出逻辑
        # 示例：简单返回成功，实际可能需要删除token等操作
        response = Response({"tools": "成功退出"}, status=status.HTTP_200_OK)
        response.delete_cookie('jwt')  # 若使用cookie存储凭证
        return response


class RegisterView(generics.CreateAPIView):
    serializer_class = UserProfileSerializer
    permission_classes = [permissions.AllowAny]

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        reset_code = PasswordResetCode.objects.filter(
            email=request.data['email'],
            code=request.data['code'],
            is_used=False
        ).latest('created_date')
        if not reset_code:
            return serializer.ValidationError('验证码无效或已过期')

        if reset_code.is_expired():
            return serializer.ValidationError('验证码已过期')
        # 保存数据
        if serializer.is_valid():
            reset_code.is_used = True
            reset_code.save()

            serializer.save()
            return Response({
                'message': '用户注册成功'
            }, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class SendVerificationCode(APIView):
    permission_classes = [AllowAny]

    def post(self, request):
        email = request.data.get('email')

        # 生成6位验证码
        code = ''.join(random.choices('0123456789', k=6))

        # 保存验证码记录
        PasswordResetCode.objects.create(email=email, code=code)

        # 发送邮件（需配置邮件设置）
        send_mail(
            'Password Reset Verification Code',
            f'Your verification code is: {code}',
            settings.EMAIL_HOST_USER,
            [email],
            fail_silently=False,
        )

        return Response({'message': '验证码已发送'})


class ResetPassword(APIView):
    permission_classes = [AllowAny]

    @transaction.atomic
    def post(self, request):
        # 验证邮箱是否存在
        email = request.data.get('email')
        if not UserProfile.objects.filter(email=email).exists():
            return Response({'error': '该邮箱未注册'}, status=400)
        serializer = PasswordResetSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        data = serializer.validated_data
        try:
            # 获取最新未使用的验证码
            reset_code = PasswordResetCode.objects.filter(
                email=data['email'],
                code=data['code'],
                is_used=False
            ).latest('created_date')
            if not reset_code:
                return Response({'error': '验证码无效或已过期'}, status=400)

            if reset_code.is_expired():
                return Response({'error': '验证码已过期'}, status=400)
            # 更新用户密码
            user = UserProfile.objects.get(email=data['email'])
            user.password = make_password(data['new_password'])
            user.save()

            # 标记验证码已使用
            reset_code.is_used = True
            reset_code.save()
        except PasswordResetCode.DoesNotExist:
            return Response({'error': '验证码无效或已过期'}, status=400)
        return Response({'message': '密码重置成功'})


class GetCSRFToken(APIView):
    permission_classes = [permissions.AllowAny]

    @csrf_exempt
    def get(self, request, format=None):
        csrf_token = get_token(request)
        return Response({'csrfToken': csrf_token})


class SocialCallbackView(APIView):
    def post(self, request, provider):
        strategy = load_strategy(request)
        backend = load_backend(strategy, provider, redirect_uri='/')

        # 执行认证流程
        user = backend.auth_complete(request)

        # 生成JWT
        refresh = RefreshToken.for_user(user)
        return Response({
            'access': str(refresh.access_token),
            'refresh': str(refresh),
            'user': UserProfileSerializer(user).data
        })


class OauthLoginView(APIView):
    permission_classes = [permissions.AllowAny]

    # 统一配置第三方登录参数
    PROVIDER_CONFIG = {
        'gitee': {
            'client_id_setting': 'GITEE_CLIENT_ID',
            'base_auth_url': 'https://gitee.com/oauth/authorize',
            'required_params': {
                'response_type': 'code',
                'scope': None  # 无额外scope
            }
        },
        'github': {
            'client_id_setting': 'GITHUB_CLIENT_ID',
            'base_auth_url': 'https://github.com/login/oauth/authorize',
            'required_params': {
                'response_type': 'code',
                'scope': 'user:email'
            }
        },
        'qq': {
            'client_id_setting': 'QQ_CLIENT_ID',
            'base_auth_url': 'https://graph.qq.com/oauth2.0/authorize',
            'required_params': {
                'response_type': 'code',
                'scope': 'get_user_info'
            }
        },
        'weibo': {
            'client_id_setting': 'WEIBO_CLIENT_ID',
            'base_auth_url': 'https://api.weibo.com/oauth2/authorize',
            'append_hash': '#wechat_redirect',
            'required_params': {
                'response_type': 'code',
               'scope': 'email'
            }
        },
    }

    def get(self, request, provider):
        # 验证支持的登录方式
        if provider not in self.PROVIDER_CONFIG:
            return Response({'error': '暂不支持该第三方登录'}, status=status.HTTP_400_BAD_REQUEST)

        config = self.PROVIDER_CONFIG[provider]

        try:
            # 动态获取客户端ID
            client_id = getattr(settings, config['client_id_setting'])

            # 构建重定向URI
            redirect_uri = f"{settings.VITE_REDIRECT_URI}{provider}"

            # 构造基础参数
            params = {
                'client_id': client_id,
                'redirect_uri': redirect_uri,
                **{k: v for k, v in config['required_params'].items() if v is not None}
            }

            # 生成认证URL
            auth_url = f"{config['base_auth_url']}?{urlencode(params)}"
            return JsonResponse({'auth_url': auth_url})

        except AttributeError as e:
            # 处理配置缺失异常
            return Response({'error': f'系统配置错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class OauthCallbackView(APIView):
    permission_classes = [permissions.AllowAny]

    # 统一配置第三方登录回调参数
    PROVIDER_CALLBACK_CONFIG = {
        'gitee': {
            'client_id_setting': 'GITEE_CLIENT_ID',
            'client_secret_setting': 'GITEE_CLIENT_SECRET',
            'token_url': 'https://gitee.com/oauth/token',
            'user_info_url': 'https://gitee.com/api/v5/user',
            'identifier': 'gitee_id',
            'user_fields': {
                'username': 'login',
                'name': 'name',
                'email': 'email',
                'url': 'html_url',
                'bio': None,
                'address': None,
            },
            'default_email': lambda username: f"{username}@gitee.com",
        },
        'github': {
            'client_id_setting': 'GITHUB_CLIENT_ID',
            'client_secret_setting': 'GITHUB_CLIENT_SECRET',
            'token_url': 'https://github.com/login/oauth/access_token',
            'user_info_url': 'https://api.github.com/user',
            'identifier': 'github_id',
            'user_fields': {
                'username': 'login',
                'name': 'name',
                'email': 'email',
                'url': 'html_url',
                'bio': None,
                'address': None,
            },
            'default_email': lambda username: f"{username}@github.com",
        },
        'qq': {
            'client_id_setting': 'QQ_CLIENT_ID',
            'client_secret_setting': 'QQ_CLIENT_SECRET',
            'token_url': 'https://graph.qq.com/oauth2.0/token',
            'openid_url': 'https://graph.qq.com/oauth2.0/me',
            'user_info_url': 'https://graph.qq.com/user/get_user_info',
            'identifier': 'qq_id',
            'user_fields': {
                'username': 'username',
                'name': 'nickname',
                'email': 'email',
                'url': None,
                'bio': None,
                'address': 'city'
            },
            'default_email': lambda openid: f"{openid}@qq.com",
            'default_name': "QQ用户",
        },
        'weibo': {
            'client_id_setting': 'WEIBO_CLIENT_ID',
            'client_secret_setting': 'WEIBO_CLIENT_SECRET',
            'token_url': 'https://api.weibo.com/oauth2/access_token',
            'user_info_url': 'https://api.weibo.com/2/users/show.json',
            'identifier': 'weibo_id',
            'requires_source_param': True,
            'user_fields': {
                'username': 'username',
                'name': 'name',
                'email': 'email',
                'url': None,
                'bio': 'description',
                'address': 'location',
            },
            'default_email': lambda username: f"{username}@weibo.com",
        },
    }

    def generate_random_username(self, length=8):
        """生成随机用户名"""
        letters = string.ascii_lowercase + string.digits
        return ''.join(random.choice(letters) for _ in range(length))

    @method_decorator(csrf_exempt)
    def get(self, request, provider):
        code = request.GET.get('code')
        if not code:
            return Response({'error': '缺少授权码'}, status=status.HTTP_400_BAD_REQUEST)

        if provider not in self.PROVIDER_CALLBACK_CONFIG:
            return Response({'error': '暂不支持该第三方登录'}, status=status.HTTP_400_BAD_REQUEST)

        config = self.PROVIDER_CALLBACK_CONFIG[provider]

        try:
            # 动态获取客户端ID和客户端密钥
            client_id = getattr(settings, config['client_id_setting'])
            client_secret = getattr(settings, config['client_secret_setting'])
            redirect_uri = settings.VITE_REDIRECT_URI + provider

            # 使用授权码获取访问令牌
            token_data = {
                'client_id': client_id,
                'client_secret': client_secret,
                'code': code,
                'grant_type': 'authorization_code',
                'redirect_uri': redirect_uri
            }

            if provider == 'qq':  # QQ的token请求是GET而不是POST
                token_response = requests.get(config['token_url'], params=token_data)
                token_response_dict = parse_qs(token_response.text)
                access_token = token_response_dict.get('access_token', [None])[0]
            else:
                token_response = requests.post(config['token_url'], data=token_data).json()
                access_token = token_response.get('access_token')

            if not access_token:
                return Response({'error': '无法获取访问令牌'}, status=status.HTTP_400_BAD_REQUEST)

            # 使用访问令牌获取用户信息
            user_info_url = config['user_info_url']
            if provider == 'qq':
                # 获取openid
                openid_response = requests.get(config['openid_url'], params={'access_token': access_token})
                response_text = openid_response.text.strip()
                try:
                    json_str = response_text.split('(', 1)[1].rsplit(')', 1)[0]
                    openid_data = json.loads(json_str)
                    user_identifier = openid_data.get('openid')
                except (IndexError, json.JSONDecodeError, KeyError) as e:
                    return Response({'error': '解析openid失败'}, status=status.HTTP_400_BAD_REQUEST)
                if not user_identifier:
                    return Response({'error': '无法获取用户openid'}, status=status.HTTP_400_BAD_REQUEST)

                # 使用访问令牌和openid获取用户信息
                user_info_params = {
                    'access_token': access_token,
                    'oauth_consumer_key': client_id,
                    'openid': user_identifier,
                    'fmt': 'json'
                }
                user_info_response = requests.get(user_info_url, params=user_info_params).json()
            elif provider == 'weibo':
                # 获取uid
                uid_response = token_response.get('uid')
                if not uid_response:
                    return Response({'error': '无法获取用户uid'}, status=status.HTTP_400_BAD_REQUEST)
                user_identifier = str(uid_response)

                # 使用访问令牌和uid获取用户信息
                user_info_params = {
                    'access_token': access_token,
                    'uid': user_identifier
                }
                user_info_response = requests.get(user_info_url, params=user_info_params).json()
            else:
                user_info_response = requests.get(user_info_url,headers={'Authorization': f'token {access_token}'}).json()
                user_identifier = user_info_response.get(config['user_fields']['username'])
            # 解析用户信息
            username = user_info_response.get(config['user_fields']['username'])#用户名
            name = user_info_response.get(config['user_fields']['name'])#昵称
            email = user_info_response.get(config['user_fields']['email'])#邮箱
            url = user_info_response.get(config['user_fields']['url'])#个人主页
            bio = user_info_response.get(config['user_fields']['bio'])#个人简介
            address = user_info_response.get(config['user_fields']['address'])#所在地

            # 处理email为空的情况
            if not email:
                email = config['default_email'](username if username else user_identifier)
            if not name and provider == 'qq':
                name = config['default_name']
            if not username:
                username = self.generate_random_username()
            if not address:
                address = '未知'

            # 检查是否成功获取用户信息
            if not user_identifier:
                return Response({'error': '无法获取用户信息'}, status=status.HTTP_400_BAD_REQUEST)

            # 使用user_identifier查询用户
            try:
                user = UserProfile.objects.get(**{config['identifier']: user_identifier})
            except UserProfile.DoesNotExist:
                # 如果用户不存在，则创建一个新用户
                user, created = UserProfile.objects.update_or_create(
                    email=email,
                    defaults={
                        'is_active': True,
                        'is_staff': False,
                        'is_superuser': False,
                    }
                )
                if created:
                    user.username = username
                    user.nickname = name
                    user.password = make_password(username)
                    setattr(user, config['identifier'], user_identifier)
                    if url:
                        setattr(user, config['identifier'], url)
                    if bio:
                        user.bio = bio
                    user.address = address
                    user.source = provider
                    user.save()

            # 生成JWT
            refresh = RefreshToken.for_user(user)
            return Response({
                'access': str(refresh.access_token),
                'refresh': str(refresh),
                'user': UserNicknameSerializer(user).data
            })

        except AttributeError as e:
            # 处理配置缺失异常
            return Response({'error': f'系统配置错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

